/*
compile:
cc svn_client_log.c -o svn_client_log  -I/usr/include/subversion-1 -I/usr/include/apr-1.0   -L/usr/lib   -lsvn_client-1 -lapr-1 -laprutil-1

run: 
./svn_client_log svn+ssh://ppquang@rd.anevia.com/svn/testing

*/

#include "svn_client.h"
#include "svn_cmdline.h"
#include "svn_pools.h"
#include "svn_config.h"
#include "svn_fs.h"
#include "svn_client_log_ios.h"

/* callback to accept server certification */
svn_error_t* sslserverprompt(svn_auth_cred_ssl_server_trust_t **cred_p, void * baton,
                             const char * realm, apr_uint32_t failures,
                             const svn_auth_ssl_server_cert_info_t * cert_info,
                             svn_boolean_t may_save, apr_pool_t *pool)
{
    *cred_p = (svn_auth_cred_ssl_server_trust_t*)apr_pcalloc (pool, sizeof (**cred_p));
    (*cred_p)->may_save = FALSE;
    return SVN_NO_ERROR;
}

/* Display a prompt and read a one-line response into the provided buffer,
   removing a trailing newline if present. */
static svn_error_t *
prompt_and_read_line(const char *prompt,
                     char *buffer,
                     size_t max)
{
    int len;
    printf("%s: ", prompt);
    /*if (fgets(buffer, max, stdin) == NULL)
    return svn_error_create(0, NULL, "error reading stdin");*/
    buffer = "Nevongat5";
    len = strlen(buffer);
    if (len > 0 && buffer[len-1] == '\n')
    buffer[len-1] = 0;
    return SVN_NO_ERROR;
}

/* A tiny callback function of type 'svn_auth_simple_prompt_func_t'. For
   a much better example, see svn_cl__auth_simple_prompt in the official
   svn cmdline client. */
static svn_error_t *
my_simple_prompt_callback (svn_auth_cred_simple_t **cred,
                           void *baton,
                           const char *realm,
                           const char *username,
                           svn_boolean_t may_save,
                           apr_pool_t *pool)
{
    svn_auth_cred_simple_t *ret = apr_pcalloc (pool, sizeof (*ret));
    char answerbuf[100];

    if (realm)
    {
        printf ("Authentication realm: %s\n", realm);
    }
    /*
    if (username)
        ret->username = apr_pstrdup (pool, username);
    else
    {
        SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
        ret->username = apr_pstrdup (pool, answerbuf);
    }

    SVN_ERR (prompt_and_read_line("Password", answerbuf, sizeof(answerbuf)));
    ret->password = apr_pstrdup (pool, answerbuf);
    */
    ret->username = repositoryForLogFetch.loginname;
    ret->password = repositoryForLogFetch.password;
    *cred = ret;
    return SVN_NO_ERROR;
}


/* A tiny callback function of type 'svn_auth_username_prompt_func_t'. For
   a much better example, see svn_cl__auth_username_prompt in the official
   svn cmdline client. */
static svn_error_t *
my_username_prompt_callback (svn_auth_cred_username_t **cred,
                             void *baton,
                             const char *realm,
                             svn_boolean_t may_save,
                             apr_pool_t *pool)
{
    svn_auth_cred_username_t *ret = apr_pcalloc (pool, sizeof (*ret));
    char answerbuf[100];

    if (realm)
    {
        printf ("Authentication realm: %s\n", realm);
    }

    SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
    ret->username = apr_pstrdup (pool, answerbuf);

    *cred = ret;
    return SVN_NO_ERROR;
}

//get log callback
static void iterate_hashtab(apr_hash_t *ht)
{
    apr_hash_index_t *hi;
    for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) {
        int commitIndex = logFetch.numberOfCommits-1;
        if (logFetch.commits[commitIndex].numberOfChanges == BID_MAX_CHANGES_PER_COMMIT){
            break;
        }else{
            logFetch.commits[commitIndex].numberOfChanges++;
        }
        const char *file;
        const char *type;
        int changeIndex = logFetch.commits[commitIndex].numberOfChanges-1;
        apr_hash_this(hi, (const void**)&file, NULL, (void**)&type);
        if (type != NULL){
            strcpy(logFetch.commits[commitIndex].changes[changeIndex].type, type);
        }else{
            strcpy(logFetch.commits[commitIndex].changes[changeIndex].type, "");
        }
        if (file != NULL){
            strcpy(logFetch.commits[commitIndex].changes[changeIndex].file, file);
        }else{
            strcpy(logFetch.commits[commitIndex].changes[changeIndex].file, "");
        }

    }
}
static svn_error_t * get_latest_revision(void *baton, apr_hash_t *changed_paths, svn_revnum_t revision, const char *author, const char *date,const char *message, apr_pool_t *pool)
{
    latestRevision = (int)revision;
    return SVN_NO_ERROR;
}
static svn_error_t * log_msg_receiver_func(void *baton, apr_hash_t *changed_paths, svn_revnum_t revision, const char *author, const char *date,const char *message, apr_pool_t *pool)
{
    logFetch.numberOfCommits++;
    int index = logFetch.numberOfCommits-1;
    logFetch.commits[index].revision = (int)revision;
    if (author != NULL){
        strcpy(logFetch.commits[index].author, author);
    }else{
        strcpy(logFetch.commits[index].author, "unknown");
    }
    if (date != NULL){
        strcpy(logFetch.commits[index].date, date);
    }else{
        strcpy(logFetch.commits[index].date, "");
    }
    if (changed_paths != NULL){
        logFetch.commits[index].numberOfChanges = 0;
        iterate_hashtab(changed_paths);
    }
    if (message != NULL){
        strcpy(logFetch.commits[index].message, message);
    }else{
        strcpy(logFetch.commits[index].message, "");
    }
    return SVN_NO_ERROR;
}

int svn_client_log_ios(int getLatestRev, int startRev, int endRev, const char *serverUrl)
{
    apr_pool_t *pool;
    svn_error_t *err;
    svn_client_ctx_t *ctx;

    if (svn_cmdline_init ("minimal_client", stderr) != EXIT_SUCCESS)
        return EXIT_FAILURE;
    // create pool
    pool = svn_pool_create (NULL);
    err = svn_fs_initialize (pool);
    if (err)
    {
        svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
        return EXIT_FAILURE;
    }
    /* fill out a client_ctx object */
    {
        if ((err = svn_client_create_context (&ctx, pool)))
        {
            svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
            return EXIT_FAILURE;
        }
        if ((err = svn_config_get_config (&(ctx->config), NULL, pool)))
        {
            svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
            return EXIT_FAILURE;
        }
        /* register callbacks */
        {
            svn_auth_provider_object_t *provider;
            apr_array_header_t *providers = apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));
            svn_auth_get_simple_prompt_provider (&provider, my_simple_prompt_callback, NULL,2, pool);
            APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
            svn_auth_get_username_prompt_provider (&provider, my_username_prompt_callback, NULL, 2, pool);
            APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
            svn_auth_get_ssl_server_trust_file_provider (&provider, pool);
            APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
            svn_auth_get_ssl_server_trust_prompt_provider (&provider, sslserverprompt, NULL, pool);
            APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
            svn_auth_open (&ctx->auth_baton, providers, pool);
            svn_auth_set_parameter(ctx->auth_baton, SVN_AUTH_PARAM_NON_INTERACTIVE, "");
            svn_auth_set_parameter(ctx->auth_baton, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
            svn_auth_set_parameter(ctx->auth_baton, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
        }
    } /* end of client_ctx setup */
    logFetch.numberOfCommits = 0; // reset index every connection
    svn_opt_revision_t start;
    svn_opt_revision_t end;
    apr_pool_t *mp;
    apr_array_header_t *arr;     
    apr_initialize();
    apr_pool_create(&mp, NULL);
    arr = apr_array_make(mp, 32, sizeof(const char*));
    *(const char**)apr_array_push(arr) = repositoryForLogFetch.url;
    if (getLatestRev == 1){ // get latest revision
        start.kind = svn_opt_revision_head;
        end.kind = svn_opt_revision_number;
        end.value.number = 1;
        err = svn_client_log2(arr, &start, &end, 1, TRUE, FALSE, get_latest_revision, NULL, ctx, pool);
    }else{
        start.kind = svn_opt_revision_number;
        start.value.number = startRev;
        end.kind = svn_opt_revision_number;
        end.value.number = endRev;
        err = svn_client_log(arr, &start, &end, TRUE, FALSE, log_msg_receiver_func, NULL, ctx, pool);
    }
    if (err){
        svn_handle_error2 (err, stdout, FALSE, "svn_client_log: ");
        return EXIT_FAILURE;
    }
    //printf("------------------------------------\n");
    //printf("latest revision: %d \n", latestRevision);
    return EXIT_SUCCESS;
}
